Lecture 4
Predictive learnings
Input = independent variables (IV) = features = predictors = X
\[x_1,…x_n\]
Output = Dependent variables (DV) = response = Y
\[Y_1,…,y_m\]
other var. that affect Y, but those values are neither observed nor
controlled (noise?)
\[Z_1,…Z_k\]
Matemathical model
\[ (1) y_k = g_k(x1,..., x_n, z_1, z_L),
=k = 1,K \]
\(y_k\) can be any row in our
dataset
Statistical model
\[ (2) y_k = f_k(x_1, .... , x_n) +
e_k, k = 1,K \]
\(f_k\) = Function of the observed
inputs \[ f_k \]
\(e_k\) = an additional random
stochastic component / error term \[ e_k
\]
If denoting \[X =
(x_1,x_2,...,x_p)\] then (2) becomes \[y_k = ƒ(X) + e_k\] even if we find the
perfect approximation of \(ƒ(X)\) we
will never be able to compute for the random factor \(e_k\)
\(f\) Is used as an estimation for
new y observations, which helps us understand the mechanism that is
produced by the data (y) output to help intervene in the future
Example 1(slide 14) (ISL p. 16-17) is an Ordinary least squares
(OLSS) regression Example 2(slide 15) (ISL, p. 16-17) OLS estimation can
be viewed as a projection onto the linear space spanned by the
regressors.
For predictions: - Focus on reducible errors
if: \[ E(Y-Ŷ)^2 =
E[f(X)+e-f̂(X)]^2\] Then \[ E(Y-Ŷ)^2 =
[f(X)-f̂(X)]^2+Var(e)\]
Where \([f(X)-f̂(X)]^2\) is reducible
and \(Var(e)\)is irreducible
For inference put focus on - Which predictors \(X\) associate with response \(y\) - Magnitude & direction -
relationship (Linear or other) - interaction effects
In ML we’re mainly focused on the predictive perspective
rather than the interference - It is however possible in some
situations to focus on both aspects at once
ESTIMATION OF ƒ
- Parametric
- Non-parametric
1. Parametric
’a priori assumption” : Relating to ro denoting reasoning or
knowledge which proceeds from theoretical deduction rather than
observation or experience, ie. “sexuality may be a factor but it cannot
be assumed a priori”
We fit the model based on our a priori assumptions. If we expect
linear fit we estimate the parameters beta (Multiple linear regression.
If you use ≈ you don’t note the error variable \(e\) as it’s an estimation)
\[ y ≈ ß_o+ß_1 X_1+ß_2 X_2+…+ß_p X_p
\] where \(ß_0,ß_1,ß_2\) and
\(ß_p\) are our estimators
For example 1 slide 23 \(income ≈
ß_0+ß_1YoE_1 +ß_2Seniority_2\)
for example 2 slide 24 (Polynominal and interaction
included),(Followup after class, incorrect) \(PI ≈ ß_o+ß_1 X_1+ß_2 X_2+…+ß_p X_p\). The
interaction changes the curvature of the 2-dimensional plane.
2. Non-parametric
No assumption; \(ƒ\) is very
flexible
Advantages: Predictive accuracy Disadvantages: Large number og
observations is required; overfitting risk; low interpretability. Non a
priori
example from class: Crumbled up paper. Imagine we have to predict the
plane of the paper, it’s incredibly difficult as the paper is all
crambled up. Sometimes in non-parametric \(ƒ\) can be considered a blackbox as it’s
borderline impossible to approximate.
will be covered in Machine Learning 2
method suitability
include_graphics("flexibilty vs interp.png")

Data partitioning
Split datasets into partitions, one for training and one for testing
Example: From Tutoral 1 we know that (dataset not included)
# library(rsample)
# set.seed(123)
# split_1 <- initial_split(df, prop = 0.6)
# train <- training(split_1)
# test <- testing(split_1)
For above; Load rsample library for the utilties
Seed for reproductibility - The seed specifies the point at which we
would like to split the dataset. Without a seed a random number will be
assigned (number assigned is not actually random but rather
pseudorandom)
define variable of split = split_1, where df is our dataframe or
tabel.
Prop defines where the dataset is split, 0.6 = 60/40, 0.5 would equal
50/50, etc.
training and testing are functions of the rsample library. using
these functions with our split variable will automatically assign the
desired split
Approaches for partitioning¨
splits will typically be done in an 80:20 fashion (prop = 0.8)
- Random split
- Tradtional technique, simplest way. Used in the book.
- Stratified split
- Considers target variable(\(y\))
and will try to group for it before split - if dataset has “1” and “0”
varlues and you pick randomly it can split the sets poorly, here
grouping them beforehand ensures data integrity for both sets
Re-sampling
include_graphics("ML process.png")

Single training data leads to inaccurate results. To avoid this
we utilize re-sampliung methods
- note from lecture 4: Data pre-process/feature engineering happens
before you do your data splits. If you want to impact your data in a
specific way after splitting to test different results you can do it
after establishing split. In practice it’s done between every step
including modelling. doing the pre-processing later is more optimal as
you get furhter insigt into your data.
if done at step 1 we average the dataset immediately. We want a pure
untouched dataset without influence frmo our actions.
if done at step 2 we standardize the mean for the whole dataset. The
same mean will be implemented in both the analyzis of the model and the
evaluation. Doing it this way is good
If done at step 3 we can do the integrations between each fold of the
model. This increases the accuracy between each fold for the next parse.
This takes a load of time due to multiple optimizations.
- data leakage: in some way the process of modelling we affect the
unseen observations with information from the training observations. Can
skew dataset and impact your error.
k-fold cross validation
We can force the training sets to be stratified throughout the k-fold
cross validation.
include_graphics("k-fold method.png")

bootstrapping
extracting of observations with replacement. out of this dataset you
can extract samples, put them back, same observation can be extracted
multiple times. Phillip will touch on this later.
include_graphics("Bootstrapping.png")

Use multiple split when practicing to get best results
Knowing this, the standard procedure for model building should be
include_graphics("Procedure modelling.png")

Errors
Training errors(MSE) \[MSE = \frac{1}{n}
\sum_{i = 1}^{n} (y_i - f̂(x_i))^2 \] Training error(RMSE) \[\sqrt MSE\]
Testing error (test MSE) \[Ave(y_o-f̂(x_o))^2\] where \(x_o,y_o\) are obs. not used to train.
Otherwise formulas are pretty much the same
overfitting
Small train error
High test error
Our model(algorithm) is trying too hard to find a suited fit
Variance of fit = Amount by which \(f̂\) would change if estimated using
different training set
bias of fit = error introduced by approximating real-life
problem in simple models
aim to minimize both
\[E(y_0-f̂(x_o))^2 = Var(f̂(x_o)) +
[bias(f̂(x_o))]^2 + Var(e)\]
where
\(E(y_0-f̂(x_o))\) = Expected test
MSE
\(Var(f̂(x_o\) = Variance of fit
\([bias(f̂(x_o))]\) = Bias of fit
\(Var(e)\) = Irreducible error
include_graphics("Method choice example.png")

On the example we have three models fitted. Dataset was simulated
based on black (true \(ƒ\)).Smoothing
spines on left graph is too aggressively trying to fit datapoints.
For the linear regression the training error is the lower yellow
square, testing errorr upper yellow square. These are the errors when we
run a LM on the dataset. For blue and green we see same relationship. As
shown here a higher flexibility model is not laways the optimal choice.
In the example we would go for the blue MSE to avoid
overfitting.
We always aim for lowest test error.
Lecture conclusions
Increase in method flexibility (more advanced methods, NN), we can
reduce the prediction error (bias). Increasing flexibility does however
have diminishing returns and will eventually increase our variance
further than reducing our bias.
Machine learning has to one-size-fits-all model, we must utilize all
tools and models available to us to treat each dataset
independently.
Lecture 4 coding 🤓
Sample formula interfaces
ames <- AmesHousing::make_ames()
# Sale price as function of neighborhood and year old
lm_lm <- lm(Sale_Price ~Neighborhood + Year_Sold, data = ames)
#lm is used to fit linear models
lm_glm <- glm(Sale_Price ~Neighborhood + Year_Sold, data = ames, family = gaussian)
#glm is used to fit generalized linear models
lm_caret <- train(Sale_Price ~Neighborhood + Year_Sold, data = ames, method = "lm")
Warning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleadingWarning: prediction from a rank-deficient fit may be misleading
lm_caret
Linear Regression
2930 samples
2 predictor
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 2930, 2930, 2930, 2930, 2930, 2930, ...
Resampling results:
RMSE Rsquared MAE
53433.06 0.5638988 36020.18
Tuning parameter 'intercept' was held constant at a value of TRUE
#train used as part of the Caret library. Documentation found in tfestimators package
In class with Ana follow-along
Tutorial 2
Problem 1: Programming The purpose of this problem is to get
comfortable with R and its facilities. We shall spendmost of the time
doing some basic computations. If you are a good programmer you will
finishthese computations quickly. First start by opening R, create a new
script and save it to your hard drive with the name: “Exercise1.R”.
Part 1
v1 <- c(1,2,2,1)
v2 <- c(2,3,3,2)
v1+v2
v1-v2
v1*v2
v3 <- c(v1,v2)
Part 2
#1
m1 <- c(1,6,3,2,4,6)
mA <- matrix(m1,ncol=2)
mA
#2
print(mA[1,])
print(mA[2,])
print(mA[3,])
print(mA[,1])
print(mA[,2])
rowSums(mA)
apply(mA, 1, FUN=min)
apply(mA, 1, FUN=max)
sort(mA[,1],decreasing = FALSE)
#3
mD <- matrix(1:1, ncol= 4, nrow=4)
mD[c(1,6,11,16)] <- 0
mD
mD <- matrix(1, nrow=4, ncol=4)
diag(mD) <- rep(0, nrow(mD))
mD
mE <- matrix(1:16, ncol=4,nrow=4,byrow=TRUE)
mE
mE[-c(3,5,6,9,16)] <- 0
mE
mi <- diag(x=1, nrow=4, ncol=4)
#4
mF <- (rbind(mD,mE))
mF
mE+mD
mE*mD
mE %*% mD #matrix product
#5
x = 1
calc_x <- {
if(x <= 0) {
print("-x^3")
} else {
if(x > 1) {
print("sqrtx")
} else {print("x^2")
}
}
}
calc_x
#6 busted måde
# h(x,n)=1 +x+x2+x3+···+xn=∑ni=0xi
# using replicate it's easy to match x to n
#func <- function(hxn)
# {
#for (j in 1:n)
#{
# x[j] = j^n
#}
# x
#}
#n = 6
#x_1 = n
#x = rep(x_1,n)
#func(hxn)
#6
func <- function(x,n)
{
sum = 0
for (j in 0:n)
{
sum = sum + x^j
}
return(sum)
}
func(x=1, n=2)
# 2^0 + 2^1 + 2^2 + 2^3
#7 fuck while loops
func2 <- function(x,n)
{
sum = 0
j = 0
while (j <= n)
{
sum = sum + x^j
j = j + 1
}
return(sum)
}
func2(x=3, n=3)
func3 <- function(x,n)
{
x1 <- c(0:x)
print(x1)
{
n1 <- (0:n)
print(n1)
}
nx1 <- x1^n1
nx1
print(sum(nx1))
}
func3(x=3, n = 3)
#8
# A room contains 100 toggle switches, originally all turned off. 100 people enter the roomin turn. The first one toggles every switch, the second one toggles every second switch, theone third every third switch, and so on until the last person, who toggles the last switch only. At the end of this process, which switches are turned on?Note:This requires alittle thinking. Don’t give up!
#rest state = 100 off
#first pass = 100 on
#second pass = 50 on, c(1:100,2) is on
#third pass =
##8 person \(i\) will flip lights
bulbs that are multiples of i
\[ i \in ({1,2,3 … 100}) \]
therefor;
\[ i,j \in ({1,2,3 … 100}) \]
Lightbulb 5 will be flipped by people that are a factor of 5 (5 is
prime number)
\[ i,5 \in ({1,5}) \] lightbulb 10
will be flipped by people that a factor of 10 \[ i,5 \in ({1,2,5,10})\]
Light bulb 40 will be flipped by people that are a factor of 40 \[ i,5 \in (1, 2, 4, 5, 8, 10, 20, 40)
\]
Example: Light bulb 25 will be flipped by factorials of 25 \[ i,25 \in ({1,5,25}) \] State 1, all
lightbulbs are off
state 2, all lightblubs are on (person 1)
state 5, every fifth light bulb is swapped. 25 is now off (person
5)
state 25, every twenthyfifth light blub is swapped. 25 is now on
(person 25)
Only the factorials of x impacts status.
Knowing this we define can make the function
which(!x)
[1] 1 4 9 16 25 36 49 64 81 100
We can also use the rep function as commented above for #6 for nicer
syntax
Line for Line:
x = rep(1,100), define x as 1 repeated 100 times (100 lightbulbs)
define the for metric, here for i in the range of x, 1:100-1. We use
-1 here to gain 0 and 1 values, which the xor command then translates to
true or false. Try printing after each line to see how x behaves.
for a rep sequence, length.out = non-negative integer. The desired
length of the output vector. Other inputs will be coerced to a double
vector and the first element taken. Ignored if NA or invalid..
Therefor length out dictates the amount of times we run the
sequence.
try playing around with with the function.
which(!x)
[1] 1 4 9 16 25 36 49 64 81 100
LS0tCnRpdGxlOiAiQWxsX2xlY3R1cmVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKTWF0aCBvcGVyYXRvcnMgZm91bmQgYXQKPGh0dHBzOi8vcnBydWltLmdpdGh1Yi5pby9zMzQxL1MxOS9mcm9tLWNsYXNzL01hdGhpblJtZC5odG1sPgoKYGBge3J9Cgo/TWF0cml4CmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHRpZHltb2RlbHMpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoY2FUb29scykKbGlicmFyeShyc2FtcGxlKQoKCmBgYAoKIyBMZWN0dXJlIDMgUEggKyBpbiBjbGFzcwoKIyMgSW4gY2xhc3MgYXNzaWdubWVudAoKIyMjIFByb2JsZW0gMS4xLzEuMgoKYGBge3J9CmJvc3RvbiA8LSByZWFkLmRlbGltKCJib3N0b25fY29ycmVjdGVkLnR4dCIsIHNraXAgPSA5LCBoZWFkZXIgPSBUUlVFKQpkaW0oYm9zdG9uKQpzdW0oaXMubmEoYm9zdG9uKSkKCmBgYAoKIyMjIHByb2JsZW0gMwoKJVw+JSBpcyBhIHBpcGluZyBmdW5jdGlvbi4gUmF0aGVyIHRoYW4gc3BlY2lmeWluZyB0aGUgdmFyaWFibGUgaSB3YW50IHRvCnRhcmdldCBmb3IgYWxsIG9wZXJhdGlvbnMgSSBoYXZlIGFscmVhZHkgcHJvbXB0ZWQgdGhlIHVwZGF0ZWQgdmFyaWFibGUuClN5bnRheCBib3N0b24gXDwtCnNlbGVjdChib3N0b24sLSJPQlMuIiwtIlRPV04iLC0iVE9XTi4iLC0iVFJBQ1QiLC0iTE9OIiwtIkxBVCIsLSJNRURWIikKd291bGQgZ2l2ZSBzYW1lIHJlc3VsdC4gUGlwaW5nIGlzIHVzZWZ1bCB3aGVuIHlvdSB3aXNoIHRvIHRvIGFkZGl0aW9uYWwKdmFyaWFibGUgdXBkYXRlcyBpbiBhIHJvdy4KCmBgYHtyfQpib3N0b24gPC0gYm9zdG9uICU+JQogIHNlbGVjdCgtIk9CUy4iLC0iVE9XTiIsLSJUT1dOLiIsLSJUUkFDVCIsLSJMT04iLC0iTEFUIiwtIk1FRFYiKQpgYGAKCiMjIyBwcm9ibGVtIDQKCnJlbWVtYmVyIHRvIHNhdmUgdmFyaWFibGUgY2hhbmdlIHRvIHRoZSB1cGRhdGVkIHZhcmlhYmxlIHVzaW5nIFw8LQoKQmUgYXdhcmUgdGhhdCBpbiB0aGlzIGV4YW1wbGUgdGhlIGxvZ2ljIGlzOgoKTmFtZXMoYm9zdG9uKSAtIHRoZSBjb2x1bW5zIG9mIGRmIGJvc3RvbiAtLCBuZWVkcyB0byBiZSBzZXQgdG8gbG93ZXIuIFdlCm5lZWQgdG8gYm90aCBzYXZlIHRoZSBsb3dlcmNhc2UgbmFtZXMgdG8gb3VyIGRhdGFmcmFtZSBhbmQgc3BlY2lmeSB3ZQp3YW50IHRoZW0gbG93ZXIsIGFzIHN1Y2ggbmFtZXMoYm9zdG9uKSkgaXMgY2FsbGVkIHR3aWNlLgoKYGBge3J9Cm5hbWVzKGJvc3RvbikgPC0gdG9sb3dlcihuYW1lcyhib3N0b24pKQoKYGBgCgojIyMgcHJvYmxlbSA1CgpgYGB7cn0KYm9zdG9uIDwtIHJlbmFtZShib3N0b24sbWVkdj1jbWVkdikKaGVhZChib3N0b24pCmBgYAoKIyMjIHByb2JsZW0gNgoKSSdtIHVzaW5nIHRoZSByZWFkciB3cml0ZV9jc3YgZnVuY3Rpb25hbGl0eS4gSXQncyBzbWFydCBhbmQga25vd3Mgd2hhdAp0byBkbyByZWdhcmRpbmcgaGVhZGVycyBldGMgYWxyZWFkeS4gSWYgeW91IHdlcmUgdG8gdXNlIGJhc2UgUiBJIHdvdWxkCmRvIHRoZSBmdW5jdGlvbiBhcyBmb2xsb3dzCgp3cml0ZS5jc3YoYm9zdG9uLCBmaWxlID0gIkJvc3RvbkJJLmNzdiIsIG5hID0gIk5BIikgc3BlY2lmeWluZyBvZgphZGRpdGlvbmFsIHBhcmFtZXRlcnMKCmBgYHtyfQp3cml0ZV9jc3YoYm9zdG9uLCAiQm9zdG9uQkkuY3N2IikKCmBgYAoKIyMjIFByb2JsZW0gMi4yCgpgYGB7cn0KYm9zdG9uMSA8LSBib3N0b24gJT4lCiAgc2VsZWN0KHRheCwgbWVkdikKICBzdW1tYXJ5KGJvc3RvbjEpCiAgY29yKGJvc3RvbjEpCgpgYGAKCiMjIyBQcm9ibGVtIDMKCmBgYHtyfQpnZ3Bsb3QoYm9zdG9uMSwgYWVzKHg9dGF4KSkgKyBnZW9tX2RlbnNpdHkoKSArIGxhYnMoeD0iVVMkIikKYGBgCgojIyMgUHJvYmxlbSA0CgpgYGB7cn0KZ2dwbG90KGJvc3RvbjEsIGFlcyh4PXRheCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1KQpgYGAKCiMjIyBwcm9ibGVtIDUKCk5lZWQgdG8gYXR0YWNoIHRoZSBkYXRhZnJhbWUgaW4gb3JkZXIgdG8gZG8gdGhlIGZhY3RvcmlhbCBvcGVyYXRpb25zLgpDb3VsZCBwcm9iYWJseSBiZSBzb2x2ZWQgYnkgcGlwaW5nPyBXaWxsIGFkZCB0byBsYXRlci4KCkZpcnN0IHdlIGRlZmluZSBvdXIgc3RyaW5nIHZhbHVlIGZhY3RvcmlhbCwgdGF4bGFiZWwuIFRoZW4gd2UgZGVmaW5lIHRoZQp2YWx1ZSBwYXJhbWV0ZXJzIGFzc2lnbmVkIHRvIHRoZSBzdHJpbmcuIElmIHRheCBpcyBsZXNzIHRoYW4gMzAwLCB0aGUKdmFsdWUgYXNzaWduZWQgaXMgbG93LCBvciAwLiBJZiBiZXR3ZWVuIDMwMCBhbmQgNjAwIHZhbHVlIGFzc2lnbmVkIGlzCm1lZGl1bSwgb3IgMS4gSWYgYWJvdmUgNjAwIHZhbHVlIGFzc2lnbmVkIGlzIGhpZ2gsIG9yIDMuCgpUaGUgZmFjdG9yKHRheF9kaXNjcmV0ZSwwOjIsdGF4bGFiZWwpIGRlZmluZXMgdGhlIHJhbmdlIHNwcmVhZCBmb3IKc3RyaW5nIHZhbHVlcyBvZiB0aGUgZmFjdG9yaWFsLgoKYGBge3J9CmF0dGFjaChib3N0b24pCnRheGxhYmVsIDwtIGMoImxvdyIsIm1lZGl1bSIsImhpZ2giKQp0YXhfZGlzY3JldGUgPC0gMCArICh0YXggPiAzMDApICsgKHRheCA8IDYwMCkKdGF4MiA8LSBmYWN0b3IodGF4X2Rpc2NyZXRlLDA6Mix0YXhsYWJlbCkKCmJvc3RvbiA8LSBjYmluZChib3N0b24sdGF4MikKCmhlYWQoYm9zdG9uKQoKCmBgYAoKIyMjIFByb2JsZW0gNgoKQ29vcmRfZmxpcCBmbGlwcyB0aGUgeCBhbmQgeSB2YWx1ZXMuIFVzZWQgaGVyZSBmb3IgaW5jcmVhc2VkCnJlYWRhYmlsaXR5LgoKYGBge3J9CmdncGxvdChib3N0b24sIGFlcyh4PXRheCx5PW1lZHYpKSArIGdlb21fYm94cGxvdCgpICsgY29vcmRfZmxpcCgpCmBgYAoKIyMjcHJvYmxlbSA3IGdncGxvdCBzeW50YXggPSBhZXMgPSBBZXN0aGV0aWMgKHVkc2VlbmRlKSBnZW9tID0gdHlwZSBvZgpjaGFydCwgcG9pbnQgPSBzY2F0dGVyLCBib3hwbG90ID0gYm94cGxvdCwgaGlzdG9ncmFtID0gaGlzdG8uCnN0YXRfc21vb3RoIGlzIGEgYmVzdCBmaXQgbW9kZWwsIHlvdSBjYW4gZGVmaW5lIG1ldGhvZCBvZiB0aGUgZml0IGJ5CihtZXRob2Q9IngiKSwgaGVyZSAibG0iIGlzIGxpbmVhciBtb2RlbCBmaXQKCmBgYHtyfQpnZ3Bsb3QoYm9zdG9uLCBhZXMoeD10YXgseT1tZWR2KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHlsaW0oMCw1MCkgKyAKICAjIHN0YXRfc21vb3RoKCkgCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJsbSIpCgoKYGBgCgojIExlY3R1cmUgNAoKIyMgUHJlZGljdGl2ZSBsZWFybmluZ3MKCklucHV0ID0gaW5kZXBlbmRlbnQgdmFyaWFibGVzIChJVikgPSBmZWF0dXJlcyA9IHByZWRpY3RvcnMgPSBYCgokJHhfMSzigKZ4X24kJAoKT3V0cHV0ID0gRGVwZW5kZW50IHZhcmlhYmxlcyAoRFYpID0gcmVzcG9uc2UgPSBZCgokJFlfMSzigKYseV9tJCQKCm90aGVyIHZhci4gdGhhdCBhZmZlY3QgWSwgYnV0IHRob3NlIHZhbHVlcyBhcmUgbmVpdGhlciBvYnNlcnZlZCBub3IKY29udHJvbGxlZCAobm9pc2U/KQoKJCRaXzEs4oCmWl9rJCQKCiMjIyBNYXRlbWF0aGljYWwgbW9kZWwKCiQkICgxKSB5X2sgPSBnX2soeDEsLi4uLCB4X24sIHpfMSwgel9MKSwgPWsgPSAxLEsgJCQKCiR5X2skIGNhbiBiZSBhbnkgcm93IGluIG91ciBkYXRhc2V0CgojIyMgU3RhdGlzdGljYWwgbW9kZWwKCiQkICgyKSAgeV9rID0gZl9rKHhfMSwgLi4uLiAsIHhfbikgKyBlX2ssICBrID0gMSxLICQkCgokZl9rJCA9IEZ1bmN0aW9uIG9mIHRoZSBvYnNlcnZlZCBpbnB1dHMgJCQgZl9rICQkCgokZV9rJCA9IGFuIGFkZGl0aW9uYWwgcmFuZG9tIHN0b2NoYXN0aWMgY29tcG9uZW50IC8gZXJyb3IgdGVybSAkJCBlX2sgJCQKCklmIGRlbm90aW5nICQkWCA9ICh4XzEseF8yLC4uLix4X3ApJCQgdGhlbiAoMikgYmVjb21lcwokJHlfayA9IMaSKFgpICsgZV9rJCQgZXZlbiBpZiB3ZSBmaW5kIHRoZSBwZXJmZWN0IGFwcHJveGltYXRpb24gb2YgJMaSKFgpJAp3ZSB3aWxsIG5ldmVyIGJlIGFibGUgdG8gY29tcHV0ZSBmb3IgdGhlIHJhbmRvbSBmYWN0b3IgJGVfayQKCiRmJCBJcyB1c2VkIGFzIGFuIGVzdGltYXRpb24gZm9yIG5ldyB5IG9ic2VydmF0aW9ucywgd2hpY2ggaGVscHMgdXMKdW5kZXJzdGFuZCB0aGUgbWVjaGFuaXNtIHRoYXQgaXMgcHJvZHVjZWQgYnkgdGhlIGRhdGEgKHkpIG91dHB1dCB0byBoZWxwCmludGVydmVuZSBpbiB0aGUgZnV0dXJlCgpFeGFtcGxlIDEoc2xpZGUgMTQpIChJU0wgcC4gMTYtMTcpIGlzIGFuIE9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgKE9MU1MpCnJlZ3Jlc3Npb24gRXhhbXBsZSAyKHNsaWRlIDE1KSAoSVNMLCBwLiAxNi0xNykgT0xTIGVzdGltYXRpb24gY2FuIGJlCnZpZXdlZCBhcyBhIHByb2plY3Rpb24gb250byB0aGUgbGluZWFyIHNwYWNlIHNwYW5uZWQgYnkgdGhlIHJlZ3Jlc3NvcnMuCgpGb3IgcHJlZGljdGlvbnM6IC0gRm9jdXMgb24gcmVkdWNpYmxlIGVycm9ycwoKaWY6ICQkIEUoWS3FtileMiA9IEVbZihYKStlLWbMgihYKV1eMiQkIFRoZW4KJCQgRShZLcW2KV4yID0gW2YoWCktZsyCKFgpXV4yK1ZhcihlKSQkCgpXaGVyZSAkW2YoWCktZsyCKFgpXV4yJCBpcyByZWR1Y2libGUgYW5kICRWYXIoZSkkaXMgaXJyZWR1Y2libGUKCkZvciBpbmZlcmVuY2UgcHV0IGZvY3VzIG9uIC0gV2hpY2ggcHJlZGljdG9ycyAkWCQgYXNzb2NpYXRlIHdpdGgKcmVzcG9uc2UgJHkkIC0gTWFnbml0dWRlICYgZGlyZWN0aW9uIC0gcmVsYXRpb25zaGlwIChMaW5lYXIgb3Igb3RoZXIpIC0KaW50ZXJhY3Rpb24gZWZmZWN0cwoKKipJbiBNTCB3ZSdyZSBtYWlubHkgZm9jdXNlZCBvbiB0aGUgcHJlZGljdGl2ZSBwZXJzcGVjdGl2ZSByYXRoZXIgdGhhbgp0aGUgaW50ZXJmZXJlbmNlKiogLSBJdCBpcyBob3dldmVyIHBvc3NpYmxlIGluIHNvbWUgc2l0dWF0aW9ucyB0byBmb2N1cwpvbiBib3RoIGFzcGVjdHMgYXQgb25jZQoKRVNUSU1BVElPTiBPRiDGkgoKMS4gIFBhcmFtZXRyaWMKMi4gIE5vbi1wYXJhbWV0cmljCgoqMS4gUGFyYW1ldHJpYyoKCioqJ2EgcHJpb3JpIGFzc3VtcHRpb24iIDogUmVsYXRpbmcgdG8gcm8gZGVub3RpbmcgcmVhc29uaW5nIG9yIGtub3dsZWRnZQp3aGljaCBwcm9jZWVkcyBmcm9tIHRoZW9yZXRpY2FsIGRlZHVjdGlvbiByYXRoZXIgdGhhbiBvYnNlcnZhdGlvbiBvcgpleHBlcmllbmNlLCBpZS4gInNleHVhbGl0eSBtYXkgYmUgYSBmYWN0b3IgYnV0IGl0IGNhbm5vdCBiZSBhc3N1bWVkIGEKcHJpb3JpIioqCgpXZSBmaXQgdGhlIG1vZGVsIGJhc2VkIG9uIG91ciBhIHByaW9yaSBhc3N1bXB0aW9ucy4gSWYgd2UgZXhwZWN0IGxpbmVhcgpmaXQgd2UgZXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgYmV0YSAoTXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24uIElmIHlvdQp1c2Ug4omIIHlvdSBkb24ndCBub3RlIHRoZSBlcnJvciB2YXJpYWJsZSAkZSQgYXMgaXQncyBhbiBlc3RpbWF0aW9uKQoKJCQgeSDiiYggw59fbyvDn18xIFhfMSvDn18yIFhfMivigKYrw59fcCBYX3AgJCQgd2hlcmUgJMOfXzAsw59fMSzDn18yJCBhbmQgJMOfX3AkCmFyZSBvdXIgZXN0aW1hdG9ycwoKRm9yIGV4YW1wbGUgMSBzbGlkZSAyMyAkaW5jb21lIOKJiCDDn18wK8OfXzFZb0VfMSArw59fMlNlbmlvcml0eV8yJAoKZm9yIGV4YW1wbGUgMiBzbGlkZSAyNCAoUG9seW5vbWluYWwgYW5kIGludGVyYWN0aW9uIGluY2x1ZGVkKSwoRm9sbG93dXAKYWZ0ZXIgY2xhc3MsIGluY29ycmVjdCkgJFBJIOKJiCDDn19vK8OfXzEgWF8xK8OfXzIgWF8yK+KApivDn19wIFhfcCQuIFRoZQppbnRlcmFjdGlvbiBjaGFuZ2VzIHRoZSBjdXJ2YXR1cmUgb2YgdGhlIDItZGltZW5zaW9uYWwgcGxhbmUuCgoqMi4gTm9uLXBhcmFtZXRyaWMqCgpObyBhc3N1bXB0aW9uOyAkxpIkIGlzIHZlcnkgZmxleGlibGUKCkFkdmFudGFnZXM6IFByZWRpY3RpdmUgYWNjdXJhY3kgRGlzYWR2YW50YWdlczogTGFyZ2UgbnVtYmVyIG9nCm9ic2VydmF0aW9ucyBpcyByZXF1aXJlZDsgb3ZlcmZpdHRpbmcgcmlzazsgbG93IGludGVycHJldGFiaWxpdHkuIE5vbiBhCnByaW9yaQoKZXhhbXBsZSBmcm9tIGNsYXNzOiBDcnVtYmxlZCB1cCBwYXBlci4gSW1hZ2luZSB3ZSBoYXZlIHRvIHByZWRpY3QgdGhlCnBsYW5lIG9mIHRoZSBwYXBlciwgaXQncyBpbmNyZWRpYmx5IGRpZmZpY3VsdCBhcyB0aGUgcGFwZXIgaXMgYWxsCmNyYW1ibGVkIHVwLiBTb21ldGltZXMgaW4gbm9uLXBhcmFtZXRyaWMgJMaSJCBjYW4gYmUgY29uc2lkZXJlZCBhCmJsYWNrYm94IGFzIGl0J3MgYm9yZGVybGluZSBpbXBvc3NpYmxlIHRvIGFwcHJveGltYXRlLgoKKndpbGwgYmUgY292ZXJlZCBpbiBNYWNoaW5lIExlYXJuaW5nIDIqCgojIyBtZXRob2Qgc3VpdGFiaWxpdHkKCmBgYHtyfQppbmNsdWRlX2dyYXBoaWNzKCJmbGV4aWJpbHR5IHZzIGludGVycC5wbmciKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgRGF0YSBwYXJ0aXRpb25pbmcKClNwbGl0IGRhdGFzZXRzIGludG8gcGFydGl0aW9ucywgb25lIGZvciB0cmFpbmluZyBhbmQgb25lIGZvciB0ZXN0aW5nCkV4YW1wbGU6IEZyb20gVHV0b3JhbCAxIHdlIGtub3cgdGhhdCAoZGF0YXNldCBub3QgaW5jbHVkZWQpCgpgYGB7cn0KIyBsaWJyYXJ5KHJzYW1wbGUpCiMgc2V0LnNlZWQoMTIzKSAKIyBzcGxpdF8xICA8LSBpbml0aWFsX3NwbGl0KGRmLCBwcm9wID0gMC42KQojIHRyYWluIDwtIHRyYWluaW5nKHNwbGl0XzEpCiMgdGVzdCA8LSB0ZXN0aW5nKHNwbGl0XzEpCmBgYAoKRm9yIGFib3ZlOyBMb2FkIHJzYW1wbGUgbGlicmFyeSBmb3IgdGhlIHV0aWx0aWVzCgpTZWVkIGZvciByZXByb2R1Y3RpYmlsaXR5IC0gVGhlIHNlZWQgc3BlY2lmaWVzIHRoZSBwb2ludCBhdCB3aGljaCB3ZQp3b3VsZCBsaWtlIHRvIHNwbGl0IHRoZSBkYXRhc2V0LiBXaXRob3V0IGEgc2VlZCBhIHJhbmRvbSBudW1iZXIgd2lsbCBiZQphc3NpZ25lZCAobnVtYmVyIGFzc2lnbmVkIGlzIG5vdCBhY3R1YWxseSByYW5kb20gYnV0IHJhdGhlcgpwc2V1ZG9yYW5kb20pCgpkZWZpbmUgdmFyaWFibGUgb2Ygc3BsaXQgPSBzcGxpdF8xLCB3aGVyZSBkZiBpcyBvdXIgZGF0YWZyYW1lIG9yIHRhYmVsLgoKUHJvcCBkZWZpbmVzIHdoZXJlIHRoZSBkYXRhc2V0IGlzIHNwbGl0LCAwLjYgPSA2MC80MCwgMC41IHdvdWxkIGVxdWFsCjUwLzUwLCBldGMuCgp0cmFpbmluZyBhbmQgdGVzdGluZyBhcmUgZnVuY3Rpb25zIG9mIHRoZSByc2FtcGxlIGxpYnJhcnkuIHVzaW5nIHRoZXNlCmZ1bmN0aW9ucyB3aXRoIG91ciBzcGxpdCB2YXJpYWJsZSB3aWxsIGF1dG9tYXRpY2FsbHkgYXNzaWduIHRoZSBkZXNpcmVkCnNwbGl0CgoqKkFwcHJvYWNoZXMgZm9yIHBhcnRpdGlvbmluZyoqwqgKCnNwbGl0cyB3aWxsIHR5cGljYWxseSBiZSBkb25lIGluIGFuIDgwOjIwIGZhc2hpb24gKHByb3AgPSAwLjgpCgooMSkgUmFuZG9tIHNwbGl0XAoKLSAgIFRyYWR0aW9uYWwgdGVjaG5pcXVlLCBzaW1wbGVzdCB3YXkuIFVzZWQgaW4gdGhlIGJvb2suCgooMikgU3RyYXRpZmllZCBzcGxpdAoKLSAgIENvbnNpZGVycyB0YXJnZXQgdmFyaWFibGUoJHkkKSBhbmQgd2lsbCB0cnkgdG8gZ3JvdXAgZm9yIGl0IGJlZm9yZQogICAgc3BsaXQgLSBpZiBkYXRhc2V0IGhhcyAiMSIgYW5kICIwIiB2YXJsdWVzIGFuZCB5b3UgcGljayByYW5kb21seSBpdAogICAgY2FuIHNwbGl0IHRoZSBzZXRzIHBvb3JseSwgaGVyZSBncm91cGluZyB0aGVtIGJlZm9yZWhhbmQgZW5zdXJlcwogICAgZGF0YSBpbnRlZ3JpdHkgZm9yIGJvdGggc2V0cwoKIyMgZXhwYW5kIHdpdGgga25vd2xlZGdlIGZyb20gPGh0dHBzOi8vYnJhZGxleWJvZWhta2UuZ2l0aHViLmlvL0hPTUwvcHJvY2Vzcy5odG1sPgoKUmUtc2FtcGxpbmcKCmBgYHtyfQppbmNsdWRlX2dyYXBoaWNzKCJNTCBwcm9jZXNzLnBuZyIpCmBgYAoKLSAgIFNpbmdsZSB0cmFpbmluZyBkYXRhIGxlYWRzIHRvIGluYWNjdXJhdGUgcmVzdWx0cy4gVG8gYXZvaWQgdGhpcyB3ZQogICAgdXRpbGl6ZSByZS1zYW1wbGl1bmcgbWV0aG9kcwoKICAgIC0gICBub3RlIGZyb20gbGVjdHVyZSA0OiBEYXRhIHByZS1wcm9jZXNzL2ZlYXR1cmUgZW5naW5lZXJpbmcKICAgICAgICBoYXBwZW5zIGJlZm9yZSB5b3UgZG8geW91ciBkYXRhIHNwbGl0cy4gSWYgeW91IHdhbnQgdG8gaW1wYWN0CiAgICAgICAgeW91ciBkYXRhIGluIGEgc3BlY2lmaWMgd2F5IGFmdGVyIHNwbGl0dGluZyB0byB0ZXN0IGRpZmZlcmVudAogICAgICAgIHJlc3VsdHMgeW91IGNhbiBkbyBpdCBhZnRlciBlc3RhYmxpc2hpbmcgc3BsaXQuIEluIHByYWN0aWNlIGl0J3MKICAgICAgICBkb25lIGJldHdlZW4gZXZlcnkgc3RlcCBpbmNsdWRpbmcgbW9kZWxsaW5nLiBkb2luZyB0aGUKICAgICAgICBwcmUtcHJvY2Vzc2luZyBsYXRlciBpcyBtb3JlIG9wdGltYWwgYXMgeW91IGdldCBmdXJodGVyIGluc2lndAogICAgICAgIGludG8geW91ciBkYXRhLgoKICAgIGlmIGRvbmUgYXQgc3RlcCAxIHdlIGF2ZXJhZ2UgdGhlIGRhdGFzZXQgaW1tZWRpYXRlbHkuIFdlIHdhbnQgYSBwdXJlCiAgICB1bnRvdWNoZWQgZGF0YXNldCB3aXRob3V0IGluZmx1ZW5jZSBmcm1vIG91ciBhY3Rpb25zLgoKICAgIGlmIGRvbmUgYXQgc3RlcCAyIHdlIHN0YW5kYXJkaXplIHRoZSBtZWFuIGZvciB0aGUgd2hvbGUgZGF0YXNldC4gVGhlCiAgICBzYW1lIG1lYW4gd2lsbCBiZSBpbXBsZW1lbnRlZCBpbiBib3RoIHRoZSBhbmFseXppcyBvZiB0aGUgbW9kZWwgYW5kCiAgICB0aGUgZXZhbHVhdGlvbi4gRG9pbmcgaXQgdGhpcyB3YXkgaXMgZ29vZAoKICAgIElmIGRvbmUgYXQgc3RlcCAzIHdlIGNhbiBkbyB0aGUgaW50ZWdyYXRpb25zIGJldHdlZW4gZWFjaCBmb2xkIG9mCiAgICB0aGUgbW9kZWwuIFRoaXMgaW5jcmVhc2VzIHRoZSBhY2N1cmFjeSBiZXR3ZWVuIGVhY2ggZm9sZCBmb3IgdGhlCiAgICBuZXh0IHBhcnNlLiBUaGlzIHRha2VzIGEgbG9hZCBvZiB0aW1lIGR1ZSB0byBtdWx0aXBsZSBvcHRpbWl6YXRpb25zLgoKICAgIC0gICBkYXRhIGxlYWthZ2U6IGluIHNvbWUgd2F5IHRoZSBwcm9jZXNzIG9mIG1vZGVsbGluZyB3ZSBhZmZlY3QgdGhlCiAgICAgICAgdW5zZWVuIG9ic2VydmF0aW9ucyB3aXRoIGluZm9ybWF0aW9uIGZyb20gdGhlIHRyYWluaW5nCiAgICAgICAgb2JzZXJ2YXRpb25zLiBDYW4gc2tldyBkYXRhc2V0IGFuZCBpbXBhY3QgeW91ciBlcnJvci4KCioqay1mb2xkIGNyb3NzIHZhbGlkYXRpb24qKgoKV2UgY2FuIGZvcmNlIHRoZSB0cmFpbmluZyBzZXRzIHRvIGJlIHN0cmF0aWZpZWQgdGhyb3VnaG91dCB0aGUgay1mb2xkCmNyb3NzIHZhbGlkYXRpb24uCgpgYGB7cn0KaW5jbHVkZV9ncmFwaGljcygiay1mb2xkIG1ldGhvZC5wbmciKQpgYGAKCioqYm9vdHN0cmFwcGluZyoqCgpleHRyYWN0aW5nIG9mIG9ic2VydmF0aW9ucyB3aXRoIHJlcGxhY2VtZW50LiBvdXQgb2YgdGhpcyBkYXRhc2V0IHlvdSBjYW4KZXh0cmFjdCBzYW1wbGVzLCBwdXQgdGhlbSBiYWNrLCBzYW1lIG9ic2VydmF0aW9uIGNhbiBiZSBleHRyYWN0ZWQKbXVsdGlwbGUgdGltZXMuIFBoaWxsaXAgd2lsbCB0b3VjaCBvbiB0aGlzIGxhdGVyLgoKYGBge3J9CmluY2x1ZGVfZ3JhcGhpY3MoIkJvb3RzdHJhcHBpbmcucG5nIikKYGBgCgpVc2UgbXVsdGlwbGUgc3BsaXQgd2hlbiBwcmFjdGljaW5nIHRvIGdldCBiZXN0IHJlc3VsdHMKCktub3dpbmcgdGhpcywgdGhlIHN0YW5kYXJkIHByb2NlZHVyZSBmb3IgbW9kZWwgYnVpbGRpbmcgc2hvdWxkIGJlCgpgYGB7cn0KaW5jbHVkZV9ncmFwaGljcygiUHJvY2VkdXJlIG1vZGVsbGluZy5wbmciKQpgYGAKCiMjIE1vZGVsIGV2YWx1YXRpb24gY3JpdGVyaWEKCiMjI3dpbGwgYmUgZXhwYW5kZWQgdXBvbgoKZXhwYW5kIHdpdGgga25vd2xlZGdlIGZyb20KPGh0dHBzOi8vYnJhZGxleWJvZWhta2UuZ2l0aHViLmlvL0hPTUwvcHJvY2Vzcy5odG1sPgoKKipSZWdyZXNzaW9uIG1vZGVsczoqKgoKKmJvbGQqID0gbW9zdCBjb21tb24KCi0gICAqKk1TRSoqIChtZWFuIHNxdWFyZWQgZXJyb3IpCgotICAgKipSTVNFKiogKHJvb3QgbWVhbiBzcXVhcmVkIGVycm9yKQoKLSAgIERldmlhbmNlCgotICAgTUFFCgotICAgUi1zcXVhcmVkCgoqKkNsYXNzaWZpY2F0aW9uIG1vZGVscyoqCgotICAgTWlzY2xhc3NpZmljYXRpb24gcmF0ZQoKLSAgIE1lYW4gcGVyIGNsYXNzIGVycm9yCgotICAgTVNFCgotICAgQ3Jvc3MtZW50cm9weQoKLSAgIEdpbmkgaW5kZXgKCi0gICBDb25mdXNpb24gbWF0cmljCgotICAgQWNjdXJhY3ksIFByZWNpc2lvbiwgU2Vuc2l0aXZpdHkvUmVjYWxsLCBTcGVjaWZpY2l0eQoKLSAgIFJPQyBhbmQgQVVDXCoKCiMjIEVycm9ycwoKVHJhaW5pbmcgZXJyb3JzKE1TRSkKJCRNU0UgPSBcZnJhY3sxfXtufSBcc3VtX3tpID0gMX1ee259ICh5X2kgLSBmzIIoeF9pKSleMiAkJCBUcmFpbmluZwplcnJvcihSTVNFKSAkJFxzcXJ0IE1TRSQkCgpUZXN0aW5nIGVycm9yICh0ZXN0IE1TRSkgJCRBdmUoeV9vLWbMgih4X28pKV4yJCQgd2hlcmUgJHhfbyx5X28kIGFyZSBvYnMuCm5vdCB1c2VkIHRvIHRyYWluLiBPdGhlcndpc2UgZm9ybXVsYXMgYXJlIHByZXR0eSBtdWNoIHRoZSBzYW1lCgojIyBvdmVyZml0dGluZwoKU21hbGwgdHJhaW4gZXJyb3IKCipIaWdoIHRlc3QgZXJyb3IqCgpPdXIgbW9kZWwoYWxnb3JpdGhtKSBpcyB0cnlpbmcgdG9vIGhhcmQgdG8gZmluZCBhIHN1aXRlZCBmaXQKCipWYXJpYW5jZSBvZiBmaXQqID0gQW1vdW50IGJ5IHdoaWNoICRmzIIkIHdvdWxkIGNoYW5nZSBpZiBlc3RpbWF0ZWQgdXNpbmcKZGlmZmVyZW50IHRyYWluaW5nIHNldAoKKmJpYXMgb2YgZml0KiA9IGVycm9yIGludHJvZHVjZWQgYnkgYXBwcm94aW1hdGluZyByZWFsLWxpZmUgcHJvYmxlbSBpbgpzaW1wbGUgbW9kZWxzCgoqYWltIHRvIG1pbmltaXplIGJvdGgqCgokJEUoeV8wLWbMgih4X28pKV4yID0gVmFyKGbMgih4X28pKSArIFtiaWFzKGbMgih4X28pKV1eMiArIFZhcihlKSQkCgp3aGVyZQoKJEUoeV8wLWbMgih4X28pKSQgPSBFeHBlY3RlZCB0ZXN0IE1TRQoKJFZhcihmzIIoeF9vJCA9IFZhcmlhbmNlIG9mIGZpdAoKJFtiaWFzKGbMgih4X28pKV0kID0gQmlhcyBvZiBmaXQKCiRWYXIoZSkkID0gSXJyZWR1Y2libGUgZXJyb3IKCmBgYHtyfQppbmNsdWRlX2dyYXBoaWNzKCJNZXRob2QgY2hvaWNlIGV4YW1wbGUucG5nIikKYGBgCgpPbiB0aGUgZXhhbXBsZSB3ZSBoYXZlIHRocmVlIG1vZGVscyBmaXR0ZWQuIERhdGFzZXQgd2FzIHNpbXVsYXRlZCBiYXNlZApvbiBibGFjayAodHJ1ZSAkxpIkKS5TbW9vdGhpbmcgc3BpbmVzIG9uIGxlZnQgZ3JhcGggaXMgdG9vIGFnZ3Jlc3NpdmVseQp0cnlpbmcgdG8gZml0IGRhdGFwb2ludHMuCgpGb3IgdGhlIGxpbmVhciByZWdyZXNzaW9uIHRoZSB0cmFpbmluZyBlcnJvciBpcyB0aGUgbG93ZXIgeWVsbG93IHNxdWFyZSwKdGVzdGluZyBlcnJvcnIgdXBwZXIgeWVsbG93IHNxdWFyZS4gVGhlc2UgYXJlIHRoZSBlcnJvcnMgd2hlbiB3ZSBydW4gYQpMTSBvbiB0aGUgZGF0YXNldC4gRm9yIGJsdWUgYW5kIGdyZWVuIHdlIHNlZSBzYW1lIHJlbGF0aW9uc2hpcC4gQXMgc2hvd24KaGVyZSBhIGhpZ2hlciBmbGV4aWJpbGl0eSBtb2RlbCBpcyBub3QgbGF3YXlzIHRoZSBvcHRpbWFsIGNob2ljZS4gKipJbgp0aGUgZXhhbXBsZSB3ZSB3b3VsZCBnbyBmb3IgdGhlIGJsdWUgTVNFIHRvIGF2b2lkIG92ZXJmaXR0aW5nKiouCgpXZSBhbHdheXMgYWltIGZvciBsb3dlc3QgdGVzdCBlcnJvci4KCiMjIExlY3R1cmUgY29uY2x1c2lvbnMKCkluY3JlYXNlIGluIG1ldGhvZCBmbGV4aWJpbGl0eSAobW9yZSBhZHZhbmNlZCBtZXRob2RzLCBOTiksIHdlIGNhbgpyZWR1Y2UgdGhlIHByZWRpY3Rpb24gZXJyb3IgKGJpYXMpLiBJbmNyZWFzaW5nIGZsZXhpYmlsaXR5IGRvZXMgaG93ZXZlcgpoYXZlIGRpbWluaXNoaW5nIHJldHVybnMgYW5kIHdpbGwgZXZlbnR1YWxseSBpbmNyZWFzZSBvdXIgdmFyaWFuY2UKZnVydGhlciB0aGFuIHJlZHVjaW5nIG91ciBiaWFzLgoKTWFjaGluZSBsZWFybmluZyBoYXMgdG8gb25lLXNpemUtZml0cy1hbGwgbW9kZWwsIHdlIG11c3QgdXRpbGl6ZSBhbGwKdG9vbHMgYW5kIG1vZGVscyBhdmFpbGFibGUgdG8gdXMgdG8gdHJlYXQgZWFjaCBkYXRhc2V0IGluZGVwZW5kZW50bHkuCgpgYGB7cn0KCmBgYAoKIyMgTGVjdHVyZSA0IGNvZGluZyDwn6STCgpTYW1wbGUgZm9ybXVsYSBpbnRlcmZhY2VzCgpgYGB7cn0KCmFtZXMgPC0gQW1lc0hvdXNpbmc6Om1ha2VfYW1lcygpCiMgU2FsZSBwcmljZSBhcyBmdW5jdGlvbiBvZiBuZWlnaGJvcmhvb2QgYW5kIHllYXIgb2xkCgpsbV9sbSA8LSBsbShTYWxlX1ByaWNlIH5OZWlnaGJvcmhvb2QgKyBZZWFyX1NvbGQsIGRhdGEgPSBhbWVzKQoKI2xtIGlzIHVzZWQgdG8gZml0IGxpbmVhciBtb2RlbHMKCmxtX2dsbSA8LSBnbG0oU2FsZV9QcmljZSB+TmVpZ2hib3Job29kICsgWWVhcl9Tb2xkLCBkYXRhID0gYW1lcywgZmFtaWx5ID0gZ2F1c3NpYW4pCgojZ2xtIGlzIHVzZWQgdG8gZml0IGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMKCmxtX2NhcmV0IDwtIHRyYWluKFNhbGVfUHJpY2Ugfk5laWdoYm9yaG9vZCArIFllYXJfU29sZCwgZGF0YSA9IGFtZXMsIG1ldGhvZCA9ICJsbSIpCmxtX2NhcmV0CgojdHJhaW4gdXNlZCBhcyBwYXJ0IG9mIHRoZSBDYXJldCBsaWJyYXJ5LiBEb2N1bWVudGF0aW9uIGZvdW5kIGluIHRmZXN0aW1hdG9ycyBwYWNrYWdlIAoKCgpgYGAKCiMjIEluIGNsYXNzIHdpdGggQW5hIGZvbGxvdy1hbG9uZwoKIyBMZWN0dXJlIDMKCnJldmlldzoKCiRrbm4kLXJlZ3Jlc3Npb24KCmstbmVhcmVzdCBuZWlnaGJvdXIsICRrJCA9IHggLSBzaW1wbGUgTUwgYWxnbyAtIGJhc2VkIG9uIGNhbGN1bGF0aW5nCmRpc3RhbmNlcyBiZXR3ZWVuIG9ic2VydmF0aW9ucyAtIGRpc3RhbmNlIGUuZy4gZXVjbGlkZWFuIChldWNsaWRlYW4Kc29ydGluZyBhbGdvKSwgTUFOSEFUVEFOLCAkZWskIGluIGEgbXVsdGlkaW1lbnNpb25hbCBzcGFjZSBvZgokWCQocHJlZGljdG9ycykgLSBwcmVkaWN0IGJ5IGF2ZXJhZ2luZyBkZXBlbmRhbnQgdmFyaWFibGVzIGZvciB0aGUKY2xvc2VzdCBLLW5laWdoYm91cnMgLSBrIGlzIHR1bmVkICh3ZSBjaGFuZ2Ugb3J1IGsgaW5wdXQgYmFzZWQgb24Kd2hhdGV2ZXIpCgotICAgay1ubiBhbGdvIGlzIGxhenkgKHNsb3csIGhhcyB0byBzb3J0IGZvciBldmVyeSBrKSwKLSAgIHdlIFNRVyg/KSBhbiBpbXBsZW1lbnRhdGlvbiBLTk4tcmVnIHVzaW5nIEFNRVMgZGF0YQoKIyMgVG9kYXk6IEZlYXR1cmUgJiB0YXJnZXQgZW5naW5lZXJpbmcgKGFsbW9zdCBzeW5vbnltb3VzIHdpdGggZGF0YSBwcmVwcm9jZXNzaW5nKQoKLSAgIFJvbGUKLSAgIFBsYWNlIGluIHRoZSBwcm9jZXNzCi0gICBoYW5kcyBvbiAkZXgkIGluIFIKClByZS1wcm9jZXNzaW5nIHN0ZXA6CgpXaGljaCBpcyBvcHRpbWFsIGluIHRlcm1zIG9mIHJlc291cmNlcyh0aW1lKSA9IGFsdGVybmF0aXZlIDIgd2hpY2ggaWRlYWwKaW4gdGVybXMgb2YgYWNjdXJhY3k/ID0gYWx0ZXJuYXRpdmUgMwoKICAgIGlmIGRvbmUgYXQgc3RlcCAxIHdlIGF2ZXJhZ2UgdGhlIGRhdGFzZXQgaW1tZWRpYXRlbHkuIFdlIHdhbnQgYSBwdXJlIHVudG91Y2hlZCBkYXRhc2V0IHdpdGhvdXQgaW5mbHVlbmNlIGZybW8gb3VyIGFjdGlvbnMuCgogICAgaWYgZG9uZSBhdCBzdGVwIDIgd2Ugc3RhbmRhcmRpemUgdGhlIG1lYW4gZm9yIHRoZSB3aG9sZSBkYXRhc2V0LiBUaGUgc2FtZSBtZWFuIHdpbGwgYmUgaW1wbGVtZW50ZWQgaW4gYm90aCB0aGUgYW5hbHl6aXMgb2YgdGhlIG1vZGVsIGFuZCB0aGUgZXZhbHVhdGlvbi4gRG9pbmcgaXQgdGhpcyB3YXkgaXMgZ29vZCAKCiAgICBJZiBkb25lIGF0IHN0ZXAgMyB3ZSBjYW4gZG8gdGhlIGludGVncmF0aW9ucyBiZXR3ZWVuIGVhY2ggZm9sZCBvZiB0aGUgbW9kZWwuIFRoaXMgaW5jcmVhc2VzIHRoZSBhY2N1cmFjeSBiZXR3ZWVuIGVhY2ggZm9sZCBmb3IgdGhlIG5leHQgcGFyc2UuIFRoaXMgdGFrZXMgYSBsb2FkIG9mIHRpbWUgZHVlIHRvIG11bHRpcGxlIG9wdGltaXphdGlvbnMKCiAgICAtIGRhdGEgbGVha2FnZTogaW4gc29tZSB3YXkgdGhlIHByb2Nlc3Mgb2YgbW9kZWxsaW5nIHdlIGFmZmVjdCB0aGUgdW5zZWVuIG9ic2VydmF0aW9ucyB3aXRoIGluZm9ybWF0aW9uIGZyb20gdGhlIHRyYWluaW5nIG9ic2VydmF0aW9ucy4gQ2FuIHNrZXcgZGF0YXNldCBhbmQgaW1wYWN0IHlvdXIgZXJyb3IuCgpXaGVuIFkgaXMgc2tld2VkIHdlIHdhbnQgdG8gdHJhbnNmb3JtIGl0LiBDb21tb24gdHJhbnNmb3JtYXRpb24gbWV0aG9kcwppbmNsdWRlIC0gTG9nIHRyYW5zZm9ybWF0aW9uIChtb3N0IGNvbW1vbiwgZG9lc24ndCBmdW5jdGlvbiBvbgowLXZhbHVlcykgLSBCb3ggQ294IHRyYW5zZm9ybWF0aW9uIChtb3N0IGZsZXhpYmxlLCBjYW4gYmUgYXBwbGllZCB0bwpwb3NpdGl2ZSBhbmQgMC12YWx1ZXMpIC0gWWVvLUpvaG5zb24gdHJhbnNtZm9ybWF0aW9uIChIYW5kbGVzIG5lZ2F0aXZlCnZhbHVlcykKClByZWRpY3Rpb25zIGZvbGxvdyB0cmFuc2Zvcm1hdGlvbiBzY2FsZSAoaWYgd2UgbG9nIHRyYW5zZm9ybSByZXN1bHQgd2lsbAphbHNvIGJlIGxvZykKCiMjIyBtaXNzaW5nIHZhbHVlcyAxIAoKLSAgIG1pc3NpbmcgdmFsdWVzIGNhbiBiZSBpbmZvcm1hdGl2ZSAoS3VobiBhbmQgSm9obnNvbiAyMDEzKQoKICAgIGRlcGVuZCBvbiBkYXRhIGNvbGVsY3Rpb24gYW5kIGRlc2VydmUgb3duIGNhdGVnb3J5CgotICAgbWlzc2luZyBhdCByYW5kb20gKExpdHRsZSBhbmQgUnViaW4gMjAxNCkgQ2FuIGJlIGRlbGV0ZWQgb3IgaW1wdXRlZAoKICAgIGluIFIsIHR5cGljYWxseSBOQSBvciBOYU4sIGFueSBhbnkgY2hhcmFjdGVyIGNhbiBkZWZpbmUgYSBtaXNpbmcsCiAgICBibGFuayBzcGFjZSBldGMuCgotICAgSWYgeW91IHdpc2ggdG8gZGl2aWRlIHZhcmlhYmxlcyBhbmQgeW91IGRpdmlkZSBieSB6ZXJvIHlvdSBjYW4gZ2V0IGEKICAgIE5BIHZhcmlhYmxlIGFzIHlvdSBjYW5ub3QgZGl2aWRlIGJ5IHplcm8uIEJlIGF3YXJlIG9mIHJhbmRvbSBtaXNzaW5nCiAgICBkYXRhIG9jY3VyaW5nCgojIyMgTWlzc2luZyB2YWx1ZXMgMgoKLSAgIFVzZSBwbG90cyB0byBpZGVudGlmeSBtaXNpbmcgZGF0YSBidW5jaC4gdXNlZnVsIGZvciBjb2xvciBjb2RpbmcKCiMjIyBpbXB1dGF0aW9uIDEKCkltcHV0YXRpb24gaXMgdXNlZCBmb3IgcmVwbGFjaW5nIG1pc3NpbmcgdmFsdWVzIHdpdGggb3VyIGJlc3QgZ3Vlc3Nlcy4KCk1ldGhvZHM6CgotICAgRXN0aW1hdGVkIHN0YXRpc3RpY3M6IE1lYW4sIE1lZGlhbiwgbW9kZSAoIGZvciBjYXRlZ29yaWNhbCkKCi0gICBLLW5lYXJlc3QgbmVpZ2hib3VycywgVHJlZS1iYXNlZCBtb2RlbHMgKHVzZSBrbm4gdG8gaW1wdXRlIG1pc3NpbmcKICAgIHZhbHVlLCB1c2UgdGhlIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlIHggbmVhcmVzdCBuZWlnaGJvdXJzIHRvCiAgICBlc3RpbWF0ZSkKCioqQXMgSW1wdXRhdGlvbiBpcyBkb25lIHdpdGhpbiByZS1zYW1wbGluZyBpdCBpbmNyZWFzZXMgcHJvY2Vzc2luZwpkZW1hbmRzLioqCgojIyMgaW1wdXRhdGlvbiAyCgpgYGB7cn0KaW5jbHVkZV9ncmFwaGljcygiSW1wdXRhdGlvbiAyLnBuZyIpCmBgYAoKTWVhbiBpbXB1dGF0aW9uIGlzIGEgY29uc3RhbnQgYXZlcmFnZSwgZGF0YSBkb2Vzbid0IGdldCBhIG5pY2UgZml0CgpLTk4gaW1wdXRhdGlvbiBlc3RpbWF0ZXMgdmFsdWVzIGJldHRlciB1c2luZyBvdGhlciBjbG9zZSB2YWx1ZXMKCkJhZ2dlZCB0cmVlcyAoZGVjaXNpb24tdHJlZSBtb2RlbD8pIEFsc28gZ2V0cyBhIGdyZWF0IGZpdC4gUHJlc2VydmVzCnJlbGF0aW9uc2hpcC4KCioqRnJvbSBoZXJlIG9uIG91dCBjb2RlYmxvY2tzIGluIGxlY3R1cmUgMyBhcmUgcmVsYXRlZCB0byB0aGUKRmVhdHVyZV9lbmdpbmVlcmluZyBSIGZpbGUgZnJvbSB0aGUgbGVjdHVyZS4qKgoKIyMjIEZlYXR1cmUgZmlsdGVyaW5nCgpXaHk/CgotICAgTW9kZWwgd2l0aCBtYW55IGZlYXR1cmVzCgogICAgLSAgIEhhcmQgdG8gaW50ZXJwcmV0CgogICAgICAgIC0gICBDb3N0bHkgdG8gY29tcHV0ZSAodGltZSwgcHJvY2Vzc2luZyBwb3dlcikKCi0gICBTb21lIG1vZGVscyBhcmUgaW5mbGV4aWJsZSB0byBub24tZm9ybWF0aXZlIHByZWRpY290cnMgKGUuZy4sKSB0aGUKICAgIGxhc3NvIG1vZGVsIGFuZCB0cmVlLWJhc2VkIG1vZGVsKS4gT3RoZXJzIGFyZSBuZWdhdGl2ZWx5IGFmZmVjdGVkLgoKYGBge3J9CgppbmNsdWRlX2dyYXBoaWNzKCJSTVNFIC0gd2l0aCBub24gZm9ybS5wbmciKQpgYGAKCkhlcmUgd2UgYXJlIHRyeWluZyBvdCB1bmRlcnRhZG4gaG93IG11Y2ggb2YgdGhlIGVycm9yIGlzIGltcGFjdGVkIGJ5IG91cgpub24gaW5mb3JtYXRpdmUgZXJyb3JzLiBPdXIgbm9uIGluZm9ybWF0aXZlIGVycm9lcyBhcmUgb3VyIFgncyB3aGVyZSB3ZQpoYXZlIG1hbnkgbWlzc2luZyB2YWx1ZXMgb3IgbWFueSBpbnZhcmlhYmxlIHZhcmlhYmxlcy4gSWYgdGhlIGRhdGEgb2YKdGhlIHZhcmlhYmxlcyBhcmUgbWlzc2luZyBvciBpbnZhcmlhYmxlIGl0IHdpbGwgaGF2ZSBubyBpbXBhY3Qgb24gb3VyCkRWLgoKLSAgIHJlbW92ZSB6ZXJvIG9yIG5lYXItemVybyB2YXJpYW5jZSBmZWF0dXJlcwoKQXMgc2VlbiBvbiB0aGUgZ3JhcGgsIG1vcmUgemVybyBvciBuZWFyLXplcm8gdmFyaWFuY2UgZmVhdHVyZXMgaW5jcmVhc2VzClJNU0UKCiMgVHV0b3JpYWwgMgoKUHJvYmxlbSAxOiBQcm9ncmFtbWluZyBUaGUgcHVycG9zZSBvZiB0aGlzIHByb2JsZW0gaXMgdG8gZ2V0IGNvbWZvcnRhYmxlCndpdGggUiBhbmQgaXRzIGZhY2lsaXRpZXMuIFdlIHNoYWxsIHNwZW5kbW9zdCBvZiB0aGUgdGltZSBkb2luZyBzb21lCmJhc2ljIGNvbXB1dGF0aW9ucy4gSWYgeW91IGFyZSBhIGdvb2QgcHJvZ3JhbW1lciB5b3Ugd2lsbCBmaW5pc2h0aGVzZQpjb21wdXRhdGlvbnMgcXVpY2tseS4gRmlyc3Qgc3RhcnQgYnkgb3BlbmluZyBSLCBjcmVhdGUgYSBuZXcgc2NyaXB0IGFuZApzYXZlIGl0IHRvIHlvdXIgaGFyZCBkcml2ZSB3aXRoIHRoZSBuYW1lOiAiRXhlcmNpc2UxLlIiLgoKUGFydCAxCgpgYGB7cn0KCnYxIDwtIGMoMSwyLDIsMSkKdjIgPC0gYygyLDMsMywyKQoKdjErdjIKdjEtdjIKdjEqdjIKdjMgPC0gYyh2MSx2MikKCmBgYAoKUGFydCAyCgpgYGB7cn0KCiMxIAptMSA8LSBjKDEsNiwzLDIsNCw2KQptQSA8LSBtYXRyaXgobTEsbmNvbD0yKQptQQoKIzIKcHJpbnQobUFbMSxdKQpwcmludChtQVsyLF0pCnByaW50KG1BWzMsXSkKcHJpbnQobUFbLDFdKQpwcmludChtQVssMl0pCgpyb3dTdW1zKG1BKQoKCmFwcGx5KG1BLCAxLCBGVU49bWluKSAKYXBwbHkobUEsIDEsIEZVTj1tYXgpIAoKc29ydChtQVssMV0sZGVjcmVhc2luZyA9IEZBTFNFKQoKIzMKCm1EIDwtIG1hdHJpeCgxOjEsIG5jb2w9IDQsIG5yb3c9NCkKCm1EW2MoMSw2LDExLDE2KV0gPC0gMAptRAoKbUQgPC0gbWF0cml4KDEsIG5yb3c9NCwgbmNvbD00KQoKZGlhZyhtRCkgPC0gcmVwKDAsIG5yb3cobUQpKSAKbUQKCgptRSA8LSBtYXRyaXgoMToxNiwgbmNvbD00LG5yb3c9NCxieXJvdz1UUlVFKQptRQptRVstYygzLDUsNiw5LDE2KV0gPC0gMAoKbUUKbWkgPC0gZGlhZyh4PTEsIG5yb3c9NCwgbmNvbD00KQoKCiM0CgptRiA8LSAocmJpbmQobUQsbUUpKQptRgoKbUUrbUQKbUUqbUQKCm1FICUqJSBtRCAjbWF0cml4IHByb2R1Y3QKCgoKIzUgCnggPSAxCmNhbGNfeCA8LSB7CiAgICBpZih4IDw9IDApIHsKICAgICAgcHJpbnQoIi14XjMiKSAKICAgIH0gZWxzZSB7CiAgICAgIGlmKHggPiAxKSB7IAogICAgICAgIHByaW50KCJzcXJ0eCIpCiAgICAgICB9IGVsc2Uge3ByaW50KCJ4XjIiKQogICAgICAgfQogICAgfQp9CiAgICAgICAKY2FsY194CgojNiBidXN0ZWQgbcOlZGUKIyBoKHgsbik9MSAreCt4Mit4MyvCt8K3wrcreG494oiRbmk9MHhpCiMgdXNpbmcgcmVwbGljYXRlIGl0J3MgZWFzeSB0byBtYXRjaCB4IHRvIG4KCiNmdW5jIDwtIGZ1bmN0aW9uKGh4bikKICMgewojZm9yIChqIGluIDE6bikKI3sKIyAgeFtqXSA9IGpebgojfQojIHgKI30KCiNuID0gNgojeF8xID0gbgojeCA9IHJlcCh4XzEsbikKCiNmdW5jKGh4bikKCiM2CmZ1bmMgPC0gZnVuY3Rpb24oeCxuKQp7CiAgc3VtID0gMAogIAogIGZvciAoaiBpbiAwOm4pCiAgewogICAgc3VtID0gc3VtICsgeF5qCiAgfQogIHJldHVybihzdW0pCn0KCmZ1bmMoeD0xLCBuPTIpCgojIDJeMCArIDJeMSArIDJeMiArIDJeMwoKIzcgZnVjayB3aGlsZSBsb29wcwogCmZ1bmMyIDwtIGZ1bmN0aW9uKHgsbikKewogIHN1bSA9IDAKICBqID0gMCAKICB3aGlsZSAoaiA8PSBuKQogIHsKICAgIHN1bSA9IHN1bSArIHheagogICAgaiA9IGogKyAxCiAgfQogIHJldHVybihzdW0pCn0KCmZ1bmMyKHg9Mywgbj0zKQoKCmZ1bmMzIDwtIGZ1bmN0aW9uKHgsbikKewp4MSA8LSBjKDA6eCkKcHJpbnQoeDEpCnsKICBuMSA8LSAoMDpuKQogIHByaW50KG4xKQp9Cm54MSA8LSB4MV5uMQpueDEKcHJpbnQoc3VtKG54MSkpCn0KCmZ1bmMzKHg9MywgbiA9IDMpCgoKICAjOAoKIyBBIHJvb20gY29udGFpbnMgMTAwIHRvZ2dsZSBzd2l0Y2hlcywgb3JpZ2luYWxseSBhbGwgdHVybmVkIG9mZi4gIDEwMCBwZW9wbGUgZW50ZXIgdGhlIHJvb21pbiB0dXJuLiAgVGhlIGZpcnN0IG9uZSB0b2dnbGVzIGV2ZXJ5IHN3aXRjaCwgdGhlIHNlY29uZCBvbmUgdG9nZ2xlcyBldmVyeSBzZWNvbmQgc3dpdGNoLCB0aGVvbmUgdGhpcmQgZXZlcnkgdGhpcmQgc3dpdGNoLCBhbmQgc28gb24gdW50aWwgdGhlIGxhc3QgcGVyc29uLCB3aG8gdG9nZ2xlcyB0aGUgbGFzdCBzd2l0Y2ggb25seS4gIEF0IHRoZSBlbmQgb2YgdGhpcyBwcm9jZXNzLCB3aGljaCBzd2l0Y2hlcyBhcmUgdHVybmVkIG9uP05vdGU6VGhpcyByZXF1aXJlcyBhbGl0dGxlIHRoaW5raW5nLiBEb27igJl0IGdpdmUgdXAhCiAgCiNyZXN0IHN0YXRlID0gMTAwIG9mZgojZmlyc3QgcGFzcyA9IDEwMCBvbgojc2Vjb25kIHBhc3MgPSA1MCBvbiwgYygxOjEwMCwyKSBpcyBvbgojdGhpcmQgcGFzcyA9IAoKCmBgYAoKIyM4IHBlcnNvbiAkaSQgd2lsbCBmbGlwIGxpZ2h0cyBidWxicyB0aGF0IGFyZSBtdWx0aXBsZXMgb2YgaQoKJCQgaSBcaW4gKHsxLDIsMyDigKYgMTAwfSkgJCQKCnRoZXJlZm9yOwoKJCQgaSxqIFxpbiAoezEsMiwzIOKApiAxMDB9KSAkJAoKTGlnaHRidWxiIDUgd2lsbCBiZSBmbGlwcGVkIGJ5IHBlb3BsZSB0aGF0IGFyZSBhIGZhY3RvciBvZiA1ICg1IGlzIHByaW1lCm51bWJlcikKCiQkIGksNSBcaW4gKHsxLDV9KSAkJCBsaWdodGJ1bGIgMTAgd2lsbCBiZSBmbGlwcGVkIGJ5IHBlb3BsZSB0aGF0IGEKZmFjdG9yIG9mIDEwICQkIGksNSBcaW4gKHsxLDIsNSwxMH0pJCQKCkxpZ2h0IGJ1bGIgNDAgd2lsbCBiZSBmbGlwcGVkIGJ5IHBlb3BsZSB0aGF0IGFyZSBhIGZhY3RvciBvZiA0MAokJCBpLDUgXGluICgxLCAyLCA0LCA1LCA4LCAxMCwgMjAsIDQwKSAkJAoKRXhhbXBsZTogTGlnaHQgYnVsYiAyNSB3aWxsIGJlIGZsaXBwZWQgYnkgZmFjdG9yaWFscyBvZiAyNQokJCBpLDI1IFxpbiAoezEsNSwyNX0pICQkIFN0YXRlIDEsIGFsbCBsaWdodGJ1bGJzIGFyZSBvZmYKCnN0YXRlIDIsIGFsbCBsaWdodGJsdWJzIGFyZSBvbiAocGVyc29uIDEpCgpzdGF0ZSA1LCBldmVyeSBmaWZ0aCBsaWdodCBidWxiIGlzIHN3YXBwZWQuIDI1IGlzIG5vdyBvZmYgKHBlcnNvbiA1KQoKc3RhdGUgMjUsIGV2ZXJ5IHR3ZW50aHlmaWZ0aCBsaWdodCBibHViIGlzIHN3YXBwZWQuIDI1IGlzIG5vdyBvbiAocGVyc29uCjI1KQoKT25seSB0aGUgZmFjdG9yaWFscyBvZiB4IGltcGFjdHMgc3RhdHVzLgoKS25vd2luZyB0aGlzIHdlIGRlZmluZSBjYW4gbWFrZSB0aGUgZnVuY3Rpb24KCmBgYHtyfQoKbGlnaHRiIDwtIGZ1bmN0aW9uKG5idWxiLCBzd2l0Y2ggPSBuYnVsYikgewogICAgYnVsYiA8LSBsb2dpY2FsKG5idWxiKQogICAgZm9yIChpaSBpbiBzZXEoc3dpdGNoKSkgewogICAgICBtYWtlMSA8LSBzZXEoaWksIG5idWxiLCBpaSkKICAgICAgYnVsYlttYWtlMV0gPC0gIWJ1bGJbbWFrZTFdCiAgICB9CiAgICB3aGljaChidWxiKQp9CgoKbGlnaHRiKDEwMCkKYGBgCgpXZSBjYW4gYWxzbyB1c2UgdGhlIHJlcCBmdW5jdGlvbiBhcyBjb21tZW50ZWQgYWJvdmUgZm9yICM2IGZvciBuaWNlcgpzeW50YXgKCkxpbmUgZm9yIExpbmU6Cgp4ID0gcmVwKDEsMTAwKSwgZGVmaW5lIHggYXMgMSByZXBlYXRlZCAxMDAgdGltZXMgKDEwMCBsaWdodGJ1bGJzKQoKZGVmaW5lIHRoZSBmb3IgbWV0cmljLCBoZXJlIGZvciBpIGluIHRoZSByYW5nZSBvZiB4LCAxOjEwMC0xLiBXZSB1c2UgLTEKaGVyZSB0byBnYWluIDAgYW5kIDEgdmFsdWVzLCB3aGljaCB0aGUgeG9yIGNvbW1hbmQgdGhlbiB0cmFuc2xhdGVzIHRvCnRydWUgb3IgZmFsc2UuIFRyeSBwcmludGluZyBhZnRlciBlYWNoIGxpbmUgdG8gc2VlIGhvdyB4IGJlaGF2ZXMuCgpmb3IgYSByZXAgc2VxdWVuY2UsIGxlbmd0aC5vdXQgPSBub24tbmVnYXRpdmUgaW50ZWdlci4gVGhlIGRlc2lyZWQKbGVuZ3RoIG9mIHRoZSBvdXRwdXQgdmVjdG9yLiBPdGhlciBpbnB1dHMgd2lsbCBiZSBjb2VyY2VkIHRvIGEgZG91YmxlCnZlY3RvciBhbmQgdGhlIGZpcnN0IGVsZW1lbnQgdGFrZW4uIElnbm9yZWQgaWYgTkEgb3IgaW52YWxpZC4uCgpUaGVyZWZvciBsZW5ndGggb3V0IGRpY3RhdGVzIHRoZSBhbW91bnQgb2YgdGltZXMgd2UgcnVuIHRoZSBzZXF1ZW5jZS4KCnRyeSBwbGF5aW5nIGFyb3VuZCB3aXRoIHdpdGggdGhlIGZ1bmN0aW9uLgoKYGBge3J9Cgp4IDwtIHJlcCgxLDEwMCkKI3ByaW50KHgpCgpmb3IgKGkgaW4gKDE6MTAwLTEpKSB7CiAgeCA8LSB4b3IoeCwgcmVwKGMocmVwKDAsaSksMSksIGxlbmd0aC5vdXQ9MTAwKSkKICAjcHJpbnQoeCkKfQp4CndoaWNoKCF4KQoKYGBgCgojIFByb2JsZW0gMiwgTGluZWFyIHJlZ3Jlc3Npb24KCiMjIyBwcm9ibGVtIDIuMQoKQ29uc2lkZXIgdGhlIHN0YW5kYXJkIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsICQkWT1YzrIrzrUkJCB3aGVyZSAkWSQgaXMKYW4tZGltZW5zaW9uYWwgb3V0Y29tZSB2ZWN0b3IsICRYJCBhbiAkbsOXcCQgZGltZW5zaW9uYWwgcmVncmVzc29yCm1hdHJpeCwgJM6yJCBhICRwJC1kaW1lbnNpb25hbCB2ZWN0b3Igb2YgY29lZmZpY2llbnRzLCBhbmQgJM61JCBhbgokbiQtZGltZW5zaW9uYWwgZXJyb3IgdGVybSB2ZWN0b3IuIFRoZSBPcmRpbmFyeUxlYXN0IFNxdWFyZXMgZXN0aW1hdG9yCmZvciAkzrIkIGlzIGdpdmVuIGJ5CgokJGhhdHvOsn09IChY4oCyWCniiJIxWOKAslkkJAoKd2hlcmUgJOKIkjEkIGRlbm90ZSB0aGUgbWF0cml4IGludmVyc2UgYW5k4oCyaXMgdGhlIG1hdHJpeCB0cmFuc3Bvc2UuIFRoZQpwcmVkaWN0aW9ucyBmcm9tIGEgbGluZWFycmVncmVzc2lvbiBtb2RlbCBhcmUgZ2l2ZW4gYnkKCiQkXGhhdHtZfT1YXGhhdHvOsn0kJAoKdGhlIHJlc2lkdWFscyBhcmUgZ2l2ZW4gYnkKCiQkZT1Z4oiSXGhhdHtZfSQkCgpUaGUgZXJyb3IgdmFyaWFuY2UgaXMgZXN0aW1hdGVkIGFzCgokJCBcaGF0e8+DfV4yPSBcZnJhY3sxfXtuLXB9IFxzdW1fe2k9MX1ee259ZV9pXjIkJCB3aGVyZSAkZWkkIGRlbm90ZSB0aGUKJGktdGgkIGVudHJ5IG9mICRlJC4gVGhlIHZhcmlhbmNlIG9mICRcaGF0e86yfSQgdW5kZXIgZnVsbCBpZGVhbApjb25kaXRpb25zIGNhbiBiZSBlc3RpbWF0ZWQgYXMgJCRcaGF0e1Z9W1xoYXR7zrJ9XSA9IFxoYXR7z4N9XjIoWOKAslgpXi0xICQkCldyaXRlIGEgZnVuY3Rpb25mT0xTKCl0aGF0IGVzdGltYXRlcyBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGFuZApwcm92aWRlcyBlc3RpbWF0aW9uIHJlc3VsdHMuIEl0IHNob3VsZCBoYXZlIHRoZSBmb2xsb3dpbmcgaW5wdXRzOgoKLSAgIEFuIGRhdGEgZnJhbWUgY29udGFpbmluZyBZYW5kIFgKCi0gICBUaGUgbGFiZWwgb3IgY29sdW1uIGVudHJ5IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGRlcGVuZGVudCB2YXJpYWJsZVkKCi0gICBUaGUgbGFiZWxzIG9yIGNvbHVtbiBlbnRyaWVzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHJlZ3Jlc3NvcnNYCgogICAgSXQgc2hvdWxkIHJldHVybiBhIGxpc3Qgb2JqZWN0IGNvbnRhaW5pbmc6CgotICAgVGhlIG51bWVyaWNhbCB2ZWN0b3Igb2YgY29lZmZpY2llbnQgZXN0aW1hdGVzy4bOsgoKLSAgIFRoZSBudW1lcmljYWwgdmVjdG9yIG9mIHByZWRpY3Rpb25zy4ZZCgotICAgVGhlIGVzdGltYXRlZCBlcnJvciB2YXJpYW5jZSDLhs+DMgoKLSAgIFRoZSBzdGFuZGFyZCBlcnJvcnMgZm9yy4bOsihIaW50OlRoZXNlIGFyZSB0aGUgc3F1YXJlLXJvb3RzIG9mIHRoZQogICAgZGlhZ29uYWwgZW50cmllcyBvZsuGVlvLhs6yXSkKCmBgYHtyfQoKPC0gYygxOjEwMCkKWSA8LSBjKDI6MTAwLDIpCmRmb2xzIDwtIGRhdGEuZnJhbWUoWCxZKQpoZWFkKGRmb2xzKQoKZk9MUyA8LSBmdW5jdGlvbigpIHsKICAKICAKICAKfQpwcmludCh4KQpgYGAK